﻿using DotNetCore.CAP;
using DotNetCore.CAP.MySql;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkCore.Domain.Abstractions;
using UnitOfWorkCore.Domain.Entities;

namespace UnitOfWorkCore.Infrastructure.Context
{

    /// <summary>
    /// 定义数据库上下文对象
    /// </summary>
    public class AppDbContext : DbContext, ITransaction//, IUnitOfWork//,
    {
        /// <summary>
        /// 用于处理领域事件和命令
        /// </summary>
        protected IMediator _mediator;

        /// <summary>
        /// 用于发布事件到消息队列或其他中间件
        /// </summary>
        //Lazy<ICapPublisher> _capBus;

        /// <summary>
        /// 构造函数，接收 DbContextOptions 参数
        /// </summary>
        /// <param name="options">用于传递数据库连接字符串、数据库提供程序等配置信息</param>
        /// <param name="mediator">用于处理领域事件和命令的 Mediator 组件</param>
        /// <param name="capBus">用于发布事件到消息队列或其他中间件的 ICapPublisher 组件</param>
        public AppDbContext(DbContextOptions options, IMediator mediator)//, Lazy<ICapPublisher> capBus)
            : base(options) // 调用基类 DbContext 的构造函数，将配置信息传递给基类
        {
            _mediator = mediator;
            //_capBus = capBus;
        }

        public virtual DbSet<User> User { get; set; }
        public virtual DbSet<Role> Role { get; set; }

        /// <summary>
        /// 配置实体模型的映射关系和数据库表结构
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder); // 调用基类的 OnModelCreating 方法，执行默认的模型构建逻辑

            // 在这里可以添加自定义的模型配置代码
            // 例如，配置实体类的表名、字段映射、关系等
            // 例如：
            // modelBuilder.Entity<YourEntity>().ToTable("YourTableName");
            // modelBuilder.Entity<YourEntity>().Property(p => p.YourProperty).IsRequired();
        }


        /// <summary>
        /// 定义一个私有字段 _currentTransaction，用于存储当前的数据库事务
        /// </summary>
        private IDbContextTransaction _currentTransaction;

        /// <summary>
        /// 获取当前正在进行的数据库事务
        /// </summary>
        /// <returns></returns>
        public IDbContextTransaction GetCurrentTransaction() => _currentTransaction;

        /// <summary>
        /// 如果有正在进行的事务，则返回 true；否则返回 false
        /// </summary>
        public bool HasActiveTransaction => _currentTransaction != null;

        /// <summary>
        /// 开始一个数据库事务
        /// </summary>
        /// <returns></returns>
        public async Task<IDbContextTransaction> BeginTransactionAsync()
        {
            // 检查是否已经有一个正在进行的事务
            if (_currentTransaction != null) return null;
            // 开始一个新的事务，并将事务对象赋值给 _currentTransaction
            _currentTransaction = await this.Database.BeginTransactionAsync();
            return await Task.FromResult(_currentTransaction);
        }

        /// <summary>
        /// 提交指定的数据库事务
        /// </summary>
        /// <param name="transaction">当前事务</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        public async Task CommitTransactionAsync(IDbContextTransaction transaction)
        {
            // 检查传入的 transaction 是否为 null
            if (transaction == null) throw new ArgumentNullException(nameof(transaction));

            // 检查传入的 transaction 是否是当前的事务
            if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");

            try
            {
                // 调用 SaveChangesAsync 方法，将更改保存到数据库
                await SaveChangesAsync();

                // 提交事务
                transaction.Commit();
            }
            catch
            {
                // 如果发生异常，调用 RollbackTransaction 方法回滚事务
                RollbackTransaction();

                // 重新抛出异常
                throw;
            }
            finally
            {
                // 释放当前事务资源
                if (_currentTransaction != null)
                {
                    _currentTransaction.Dispose();
                    _currentTransaction = null;
                }
            }
        }

        // 回滚当前的数据库事务
        public void RollbackTransaction()
        {
            try
            {
                // 如果有正在进行的事务，调用 Rollback 方法回滚事务
                _currentTransaction?.Rollback();
            }
            finally
            {
                // 释放当前事务资源
                if (_currentTransaction != null)
                {
                    _currentTransaction.Dispose();
                    _currentTransaction = null;
                }
            }
        }
    }
}
